package com.chainyoung.component_tmperson.ui.activity.hdwallet;

import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.chainyoung.common.appcommon.entity.EthPrice;
import com.chainyoung.common.appcommon.entity.HdWalletCache;
import com.chainyoung.common.appcommon.entity.HdWalletTokenCache;
import com.chainyoung.common.appcommon.hdwallet.ExchangeCalculator;
import com.chainyoung.common.appcommon.hdwallet.WalletStoreManger;
import com.chainyoung.common.base.BaseActivity;
import com.chainyoung.common.constant.LibConstant;
import com.chainyoung.common.di.AppComponent;
import com.chainyoung.common.utils.SPUtil;
import com.chainyoung.common.utils.StringUtil;
import com.chainyoung.common.utils.ToastUtil;
import com.chainyoung.common.view.kprogresshud.KProgressHUD;
import com.chainyoung.component_tmperson.R;
import com.chainyoung.component_tmperson.R2;
import com.chainyoung.component_tmperson.di.component.DaggerPersonActivityComponent;
import com.chainyoung.component_tmperson.di.module.PersonActivityModule;
import com.chainyoung.common.appcommon.hdwallet.OwnWalletUtils;
import com.chainyoung.component_tmperson.ui.activity.cloudwallet.MyPurseAddrActivity;
import com.chainyoung.component_tmperson.ui.activity.ScanQrCodeActivity;
import com.chainyoung.component_tmperson.ui.mvp.contract.HdWalletSendTransactionContract;
import com.chainyoung.component_tmperson.ui.mvp.presenter.HdWalletSendTransactionPresenter;
import com.google.gson.Gson;

import org.json.JSONException;
import org.spongycastle.util.encoders.Hex;
import org.web3j.abi.FunctionEncoder;

import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import butterknife.BindView;
import butterknife.OnClick;

import static com.chainyoung.common.appcommon.hdwallet.CoinConstant.ETH;
import static com.chainyoung.common.appcommon.hdwallet.WalletServerConstant.CHAIN_ID;


/**
 * HD 钱包转出
 */
public class HdWalletSendTranscationActivity extends BaseActivity<HdWalletSendTransactionPresenter> implements HdWalletSendTransactionContract.View {


    @BindView(R2.id.tv_addr)
    EditText tvAddr;
    @BindView(R2.id.iv_purse)
    ImageView ivPurse;
    @BindView(R2.id.view1)
    View view1;
    @BindView(R2.id.txt2)
    TextView txt2;
    @BindView(R2.id.tv_num)
    EditText tvNum;
    @BindView(R2.id.et_optional)
    EditText etOptional;
    @BindView(R2.id.tv_fee_type)
    TextView tvFeeType;
    @BindView(R2.id.tv_fee_percent)
    TextView tvFeePercent;
    @BindView(R2.id.tv_setting)
    TextView tvSetting;
    @BindView(R2.id.seekBar)
    SeekBar seekBar;
    @BindView(R2.id.txt_slow)
    TextView txtSlow;
    @BindView(R2.id.txt_middle)
    TextView txtMiddle;
    @BindView(R2.id.txt_fast)
    TextView txtFast;
    @BindView(R2.id.txt_gas_limit)
    TextView txtGasLimit;
    @BindView(R2.id.et_gas)
    EditText etGas;
    @BindView(R2.id.rl_gas)
    RelativeLayout rlGas;
    @BindView(R2.id.tv_confirm)
    TextView tvConfirm;
    @BindView(R2.id.rl_1)
    RelativeLayout rl1;
    @BindView(R2.id.tv_caculate)
    TextView tvCaculate;
    @BindView(R2.id.tv_own_balance)
    TextView tvOwnBalance;


    private HdWalletCache hdWallet;//钱包
    private boolean isShowGas;
    private BigDecimal oriGasPrice;//初始Gas price  单位Gwei
    private BigDecimal actualGasPrice;//用户实际Gas price
    private BigDecimal oriGasLimit = BigDecimal.valueOf(22800);//gaslimit

    private BigDecimal ethRate = BigDecimal.valueOf(6.8409);//eth 对CNY 汇率
    private EthPrice ethPrice = null;
    private BigDecimal ethCny;//eth CNY价格


    private HdWalletTokenCache hdWalletTokenCache;//代币


    @Override
    protected void setupActivityComponent(AppComponent appComponent) {
        DaggerPersonActivityComponent.builder()
                .appComponent(appComponent)
                .personActivityModule(new PersonActivityModule(this))
                .build()
                .inject(this);
    }

    @Override
    protected void initUI() {
        hdWallet = (HdWalletCache) getIntent().getSerializableExtra("hdWallet");
        hdWalletTokenCache = (HdWalletTokenCache) getIntent().getSerializableExtra("hdWalletTokenCache");
        setCurrentTitle(hdWalletTokenCache == null ? "发送" : hdWalletTokenCache.getTokenSymbol()+"发送");
        oriGasLimit=hdWalletTokenCache==null?new BigDecimal(22800):new BigDecimal(430000);
        seekBar.setMax(50);
        etGas.setText(oriGasLimit + "");
        tvFeeType.setText(String.format(getString(R.string.transfer_money), hdWallet.getCoinType()));
        Drawable drawable=ContextCompat.getDrawable(mContext,R.mipmap.ic_scan);
        DrawableCompat.setTint(drawable, Color.parseColor("#061c69"));
        showAndSetBarRightIcon(drawable);
        tvOwnBalance.setText(hdWalletTokenCache == null ? "当前余额 " + hdWallet.getBalance() + hdWallet.getCoinType() :
                "当前余额 " + hdWallet.getBalance() + hdWallet.getCoinType() + "  " + hdWalletTokenCache.getTokenSymbol() + hdWalletTokenCache.getBalance());
        setListener();
    }

    private void setListener() {
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (oriGasPrice == null) {
                    ToastUtil.showToast("未能获取到当前GasPrice");
                    return;
                }
                if (progress == 0) {
                    actualGasPrice = oriGasPrice;
                } else {
                    actualGasPrice = oriGasPrice.multiply(new BigDecimal(progress));
                }
                setGasFee();
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        etGas.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (TextUtils.isEmpty(s.toString())) {
                    etGas.setText("0");
                }
                oriGasLimit = new BigDecimal(etGas.getText().toString());
                if (oriGasLimit.compareTo(BigDecimal.valueOf(21000)) < 0) {
                    etGas.setError("Gas limit需要大于21000");
                }
                setGasFee();
            }
        });

        tvNum.addTextChangedListener(new TextWatcher() {
            boolean deleteLastChar;// 是否需要删除末尾

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

                if (s.toString().contains(".")) {
                    // 如果点后面有超过6位数值,则删掉最后一位
                    int length = s.length() - s.toString().lastIndexOf(".");
                    // 说明后面有6位数值
                    deleteLastChar = length >= 10;
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
                if (TextUtils.isEmpty(s.toString())) {
                    return;
                }
                if (deleteLastChar) {
                    // 设置新的截取的字符串
                    tvNum.setText(s.toString().substring(0, s.toString().length() - 1));
                    // 光标强制到末尾
                    tvNum.setSelection(tvNum.getText().length());
                    KProgressHUD.create(mContext)
                            .setCustomView(mContext, R.drawable.tips_error)
                            .setLabel(getString(R.string.tmtrade_only_eight))
                            .show().setDuration(1500);
                }


                // 以小数点开头，前面自动加上 "0"
                if (s.toString().startsWith(".")) {
                    tvNum.setText("0" + s);
                    tvNum.setSelection(tvNum.getText().length());
                }
                if (s.toString().startsWith("0") && (s.toString().length() > 1) && !s.toString().startsWith("0.")) {
                    tvNum.setText(s.toString().substring(1));
                    tvNum.setSelection(tvNum.getText().length());
                }

                if (new BigDecimal(hdWallet.getBalance()).compareTo(BigDecimal.ZERO) <= 0 && new BigDecimal(tvNum.getText().toString().trim()).compareTo(BigDecimal.ZERO) != 0) {
                    tvNum.setText("0");
                    tvNum.setSelection(tvNum.getText().length());
                    return;
                }


                if (hdWalletTokenCache != null) {
                    if (new BigDecimal(tvNum.getText().toString().trim()).compareTo(new BigDecimal(hdWalletTokenCache.getBalance())) >0) {
                        KProgressHUD.create(mContext)
                                .setCustomView(mContext, R.drawable.tips_error)
                                .setLabel(String.format(getString(R.string.tmperson_transfer_coin_not_enough),hdWalletTokenCache.getTokenSymbol()))
                                .show().setDuration(1500);
                        tvNum.setText(hdWalletTokenCache.getBalance());
                        tvNum.setSelection(tvNum.getText().toString().length());
                    }
                } else {
                    if (new BigDecimal(tvNum.getText().toString()).compareTo(new BigDecimal(hdWallet.getBalance())) >= 0 && new BigDecimal(hdWallet.getBalance()).compareTo(BigDecimal.ZERO) > 0) {
                        if (actualGasPrice == null) {
                            tvNum.setText(s.toString());
                            return;
                        }
                        KProgressHUD.create(mContext)
                                .setCustomView(mContext, R.drawable.tips_error)
                                .setLabel(String.format(getString(R.string.tmperson_transfer_coin_not_enough),hdWallet.getCoinType()))
                                .show().setDuration(1500);
                        BigDecimal ethFee = oriGasLimit.multiply(actualGasPrice).divide(ExchangeCalculator.ONE_GWEI, 8, RoundingMode.DOWN);
                        BigDecimal actualMax = new BigDecimal(hdWallet.getBalance()).subtract(ethFee).setScale(8, RoundingMode.DOWN);
                        tvNum.setText(actualMax.compareTo(BigDecimal.ZERO) >= 0 ? actualMax.stripTrailingZeros().toPlainString() : "0");
                        tvNum.setSelection(tvNum.getText().toString().length());
                    }
                }
            }
        });

    }

    @Override
    protected void initData() {
        getGasPrice();

    }

    @Override
    protected int getLayoutId() {
        return R.layout.tmperson_activity_send_transaction;
    }


    @OnClick(R2.id.tv_setting)
    void showOrHideGas() {
        isShowGas = !isShowGas;
        rlGas.setVisibility(isShowGas ? View.VISIBLE : View.GONE);
        tvSetting.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, isShowGas ? R.mipmap.ic_triangle_up : R.mipmap.ic_triangle_down, 0);
    }

    @OnClick(R2.id.tv_confirm)
    void confirmSend() {
        if (actualGasPrice == null) {
            ToastUtil.showToast("请检查网络");
            return;
        }
        if (StringUtil.viewGetTextIsEmpty(tvAddr)) {
            ToastUtil.showToast("请输入地址");
            return;
        }

        if (!StringUtil.isETHWalletAddrValidate(tvAddr.getText().toString().trim())) {
            ToastUtil.showToast("请输入正确的钱包地址");
            return;
        }

        if (new BigDecimal(hdWallet.getBalance()).compareTo(BigDecimal.ZERO) <= 0) {
            ToastUtil.showToast("您的余额不足");
            return;
        }

        if (StringUtil.viewGetTextIsEmpty(tvNum)) {
            ToastUtil.showToast("请输入数量");
            return;
        }

        if (new BigDecimal(StringUtil.viewGetText(tvNum)).compareTo(BigDecimal.ZERO) <= 0) {
            ToastUtil.showToast("转入数量不能小于等于0");
            return;
        }
        if (oriGasLimit.compareTo(BigDecimal.valueOf(21000)) < 0) {
            ToastUtil.showToast("Gas limit需要大于21000");
            return;
        }
        if (oriGasPrice.compareTo(BigDecimal.valueOf(7500000))>0){
            ToastUtil.showToast("Gas limit目前最大为7500000");
            return;
        }
        getNonce();

    }

    private static final int REQUEST_ADDR = 0x001;
    private static final int REQUEST_ADDR_PURSE = 0x002;


    @Override
    public void onRightImgClicked(View v) {
        super.onRightImgClicked(v);
        Intent intent = new Intent(mContext, ScanQrCodeActivity.class);
        mContext.startActivityForResult(intent, REQUEST_ADDR);
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) {
            return;
        }
        switch (requestCode) {
            case REQUEST_ADDR:
                String addr = data.getStringExtra("data");
                List<String> wordsList = new ArrayList<>();
                if (addr.contains(":")) {
                    addr = addr.substring(addr.lastIndexOf(":") + 1);
                }
                try {
                    wordsList.addAll(Arrays.asList(addr.split(" ")));
                } catch (Exception ignore) {

                }
                if (wordsList.size() == 12) {
                    addr = OwnWalletUtils.getWalletAddr(addr, ETH);
                } else if (addr.contains(":")) {
                    addr = addr.substring(addr.lastIndexOf(":") + 1);
                }

                tvAddr.setText(addr);
                tvAddr.setSelection(addr.length());

                break;
            case REQUEST_ADDR_PURSE:
                String addr1 = data.getStringExtra("data");
                if (addr1.contains(":")) {
                    addr1 = addr1.substring(addr1.lastIndexOf(":") + 1);
                }
                tvAddr.setText(addr1);
                tvAddr.setSelection(addr1.length());
                break;
        }


    }

    @OnClick(R2.id.iv_purse)
    void selectPurse() {
        Intent intent = new Intent(mContext, MyPurseAddrActivity.class);
        intent.putExtra("selectLocalAddr", true);
        mContext.startActivityForResult(intent, REQUEST_ADDR_PURSE);
    }


    @Override
    protected void onResume() {
        super.onResume();

    }

    private void setGasFee() {
        if (actualGasPrice == null) {
            ToastUtil.showToast("未能获取到当前GasPrice");
            return;
        }
        if (ethCny == null) {
            ToastUtil.showToast("未能获取到当前ETH CNY价格");
            return;
        }
        BigDecimal ethFee = oriGasLimit.multiply(actualGasPrice).divide(ExchangeCalculator.ONE_GWEI, 8, RoundingMode.DOWN);
        BigDecimal ethCnyTotal = ethFee.multiply(ethCny);
        tvFeePercent.setText(String.format("%s ETH≈CNY %s", ethFee.setScale(8, BigDecimal.ROUND_DOWN).toPlainString(), ethCnyTotal.setScale(2, BigDecimal.ROUND_DOWN)));
        tvCaculate.setText(String.format("≈Gas(%s)*Gas Price(%s GWEI)", oriGasLimit.setScale(0, RoundingMode.DOWN), actualGasPrice.setScale(2, RoundingMode.DOWN)));

    }


    //----------------------------------------------ETH 请求------------------------------------------------------------

    private void getGasPrice() {
        mPresenter.getGasPrice();
    }

    private void getUsdCnyRate() {
        mPresenter.getUsdCnyRate("usd", "cny");
    }

    private void getEthPrice() {
        mPresenter.getEthPrice();
    }

    private void getNonce() {
        mPresenter.getNonce(hdWallet.getAddress());
    }

    @Override
    public void onGetGasPriceSuccess(String data) {
        //此处为提高成交速率，gas price 默认获取到的加2
        BigInteger[] gasPriceGwei = new BigInteger(data.substring(2), 16).divideAndRemainder(new BigInteger(String.valueOf(1000000000)));
        String gasPriceStr = gasPriceGwei[0] + "." + gasPriceGwei[1];
        oriGasPrice = new BigDecimal(gasPriceStr).add(new BigDecimal(2)).setScale(2, RoundingMode.DOWN);
        actualGasPrice = oriGasPrice;
        getUsdCnyRate();
    }

    @Override
    public void onGetNonce(String nonce) throws JSONException, CipherException, IOException {
        BigInteger tradeNonce = new BigInteger(nonce.substring(2), 16);
        //此处区分ETH发送和代币发送
        RawTransaction tx = RawTransaction.createTransaction(
                tradeNonce,
                new BigInteger(String.valueOf(actualGasPrice.multiply(ExchangeCalculator.ONE_GWEI).setScale(0, RoundingMode.DOWN))),
                new BigInteger(String.valueOf(oriGasLimit)),
                hdWalletTokenCache == null ? tvAddr.getText().toString().trim() : hdWalletTokenCache.getContractAddress(),//区分合约地址和以太坊地址
                hdWalletTokenCache == null ? new BigDecimal(tvNum.getText().toString().trim()).multiply(ExchangeCalculator.ONE_ETHER).toBigInteger() : BigInteger.ZERO,
                hdWalletTokenCache == null ? etOptional.getText().toString() : getSendTokenData()
        );
        final Credentials keys = WalletStoreManger.getFullWallet(SPUtil.getString(LibConstant.PIN_CODE), OwnWalletUtils.getAccountFilePath(hdWallet));
        byte[] signed = TransactionEncoder.signMessage(tx, (byte) CHAIN_ID, keys);
        mPresenter.sendTransaction("0x" + Hex.toHexString(signed));
    }

    /**
     * 代币发送 data 值
     */
    private String getSendTokenData() {
        List<Type> inputParameters = new ArrayList<>();
        List<TypeReference<?>> outputParameters = new ArrayList<>();
        String addr = tvAddr.getText().toString().trim();
        Address tAddress = new Address(addr.startsWith("0x") ? addr.substring(2) : addr);
        Uint256 value = new Uint256(new BigDecimal(tvNum.getText().toString().trim()).multiply(ExchangeCalculator.ONE_ETHER).toBigInteger());
        inputParameters.add(tAddress);
        inputParameters.add(value);
        TypeReference<Address> typeReference1 = new TypeReference<Address>() {
        };
        TypeReference<Uint256> typeReference2 = new TypeReference<Uint256>() {
        };
        outputParameters.add(typeReference1);
        outputParameters.add(typeReference2);
        Function function = new Function("transfer",
                inputParameters, outputParameters);
        return FunctionEncoder.encode(function);
    }

    @Override
    public void onGetEthPriceSuccessed(String data) {
        ethPrice = new Gson().fromJson(data, EthPrice.class);
        ethCny = new BigDecimal(ethPrice.getEthusd()).multiply(ethRate);
        //防止断网之后重新请求的 seekbar归0
        seekBar.setProgress(0);
        tvNum.setText("");
        setGasFee();
    }

    @Override
    public void onGetUsdCnyRateSuccessed(String data) {
        ethRate = new BigDecimal(data);
        getEthPrice();
    }


    @Override
    public void onSendTransactionSuccess(String hash) {
        ToastUtil.showToast("交易发送成功");
        finish();
    }


}
